/* **********************************************************************
版本: 2022.3.62f1
作者: wzz
日期: 2025-8-1
描述: websocket 与 tcp 的管理类
***********************************************************************/

using System.Collections.Generic;
using System.Net;
using System.Text;

namespace Framework
{
    using NetEvent = KeyValuePair<NetMgr.ENetCode, string>;

    public class NetMgr : MonoSingleton<NetMgr>
    {
        public enum ENetCode
        {
            /// <summary>
            /// 连接失败
            /// </summary>
            ConnectError,
            /// <summary>
            /// 成功连接
            /// </summary>
            Connected,
            /// <summary>
            /// 成功连接后的所有断开连接（主动Destroy除外）
            /// </summary>
            Disconnect,
        }

        // 消息队列
        private readonly Queue<byte[]> mReceiveMsgBytes = new Queue<byte[]>();
        private readonly Queue<NetEvent> mNetEvent = new Queue<NetEvent>();

        // 每帧处量消息的最大次数
        public int dealWithMsgMax = 6;
        private int needDealWithMsgNum = 0;

        private IBaseNet mCurNet;
        public FixDataAdpter FixDataAdpter { get; private set; }

        private bool mIsWebGL = false;

        public override void Init()
        {
            FixDataAdpter = new FixDataAdpter(FixDataAdpter.FixedHeaderType.Ushort);
        }

        /// <summary>
        /// 异步连接
        /// </summary>
        /// <param name="ip"></param>
        /// <param name="port"></param>
        public void ConnectAsync(string ip, int port)
        {
            IPAddress ipAddress;
            if (!IPAddress.TryParse(ip, out ipAddress))
            {
                LogWarning("请输入正确的ip地址");
                return;
            }

            if (mCurNet != null)
            {
                // 内部处理，异常捕获 正在连接中，重复连接等情况
                mCurNet.ConnectAsync(ip, port);
                return;
            }

            if (mIsWebGL)
            {
                // websocket
            }
            else
            {
                mCurNet = new NetTcpClient(this, FixDataAdpter);
                //mCurNet = new NetTcp(this);
            }
            mReceiveMsgBytes.Clear();

            mCurNet.ConnectAsync(ip, port);
        }

        // Update is called once per frame
        private void Update()
        {
            // 各连接状态通知事件
            if (mNetEvent.Count > 0)
            {
                lock (mNetEvent)
                {
                    while (mNetEvent.Count > 0)
                    {
                        DispatcherNetEvent(mNetEvent.Dequeue());
                    }
                }
            }

            // 正常消息byte[]
            if (mReceiveMsgBytes.Count > 0)
            {
                needDealWithMsgNum = dealWithMsgMax;
                lock (mReceiveMsgBytes)
                {
                    while (mReceiveMsgBytes.Count > 0 && needDealWithMsgNum > 0)
                    {
                        needDealWithMsgNum--;
                        OnReceived(mReceiveMsgBytes.Dequeue());
                    }
                }
            }
        }

        /// <summary>
        /// 处理事件
        /// </summary>
        /// <param name="netEvent"></param>
        private void DispatcherNetEvent(NetEvent netEvent)
        {
            switch (netEvent.Key)
            {
                case ENetCode.Connected:
                    OnConnected();
                    break;

                case ENetCode.Disconnect:
                    OnDisconnect(netEvent.Value);
                    break;

                case ENetCode.ConnectError:
                    OnConnectError(netEvent.Value);
                    break;

                default:
                    break;
            }
        }

        /// <summary>
        /// （主线程调用）已经连接
        /// </summary>
        public void OnConnected()
        {
            TouchSocketView.Instance.AddLog("连接成功");
        }

        /// <summary>
        /// （主线程调用）断开连接
        /// </summary>
        public void OnDisconnect(string errorMsg = null)
        {
            TouchSocketView.Instance.AddLog($"OnDisconnect:{errorMsg}");
        }

        /// <summary>
        /// （主线程调用）连接失败
        /// </summary>
        public void OnConnectError(string errorMsg = null)
        {
            TouchSocketView.Instance.AddLog($"OnConnectError:{errorMsg}");
        }

        /// <summary>
        /// （主线程调用）收到信息
        /// </summary>
        /// <param name="bytes">已解完包的数据</param>
        public void OnReceived(byte[] bytes)
        {
            var msg = $"收到：{bytes.Length} 字节，内容：{Encoding.UTF8.GetString(bytes)}";
            TouchSocketView.Instance.AddLog(msg);
        }

        /// <summary>
        /// 将异步事件，压入队列，主线程出队
        /// </summary>
        public void PupNetEvent(ENetCode netcode, string msg)
        {
            var netEvent = new NetEvent(netcode, msg);
            lock (mNetEvent)
            {
                mNetEvent.Enqueue(netEvent);
            }
        }

        /// <summary>
        /// 将异步事件，压入队列，主线程出队
        /// </summary>
        public void PupReceiveMsgBytes(byte[] bytes)
        {
            lock (mReceiveMsgBytes)
            {
                mReceiveMsgBytes.Enqueue(bytes);
            }
        }

        /// <summary>
        /// 发送消息
        /// </summary>
        /// <param name="bytes"></param>
        public void SendMsg(byte[] bytes)
        {
            if (mCurNet == null)
            {
                LogWarning("网络未启动，无法发送信息");
                return;
            }
            mCurNet.SendMsg(bytes);
        }

        /// <summary>
        /// 清理已收到消息队列
        /// </summary>
        public void ClearReceiveMsgBytes()
        {
            lock (mReceiveMsgBytes)
            {
                mReceiveMsgBytes.Clear();
            }
        }

        /// <summary>
        /// 警告信息
        /// </summary>
        public void LogWarning(string log)
        {
            LogPro.DebugPro.LogWarning(log);
        }

        /// <summary>
        /// 销毁
        /// </summary>
        public void Destroy()
        {
            if (mCurNet != null)
            {
                mCurNet.Destroy();
                mCurNet = null;
            }
        }

        private void OnDestroy()
        {
            Destroy();
        }
    }
}